
import env from './env';
import Slot from './slot';
import Painter from './painter';
import Tracker from './tracker';
import { ConfigCandidate } from './conf';

const DEFAULT_MIN = 1;
const DEFAULT_MAX = 120;

class Handler {
  constructor(args) {
    const { pixi, assetPath, sendStatus, params } = args;
    this.sendStatus = sendStatus;

    /** @type {number} */ const min = (params.min == 0) ? 0 : params.min || DEFAULT_MIN;
    /** @type {number} */ const max = (params.max == 0) ? 0 : params.max || DEFAULT_MAX;
    if (min < 0) { min = 0; } else if (min > 999) { min = 999; }
    if (max < min) { max = min; } else if (max > 999) { max = 999; }

    // DEBUG
    this.signal = {
      // 这个是按钮状态. 按钮按了就是 true
      pressed : [true, true, true],
      // 记录三个 slot 在不在滚动, true = 停了
      stop : [true, true, true],
      startAll : function () {
        this.pressed.fill(false);
      },
      stopAll : function () {
        this.pressed.fill(true);
      }
    };

    for (let i = min; i <= max; i++) {
      let figureText = (i < 10) ? "00" + i :
        ((i < 100) ? "0" + i : i.toString());

      env.conf.candidates.push(
        new ConfigCandidate([figureText[0], figureText[1], figureText[2]], 10)
      );
    }

    this.hardReset();

    this.painter = new Painter({
      PIXI : pixi,
      ticker : () => this.tick(),
      assetPath,
      env,
      events : {
        machineBegin : () => this.machineBegin(),
        machineEnd : (index) => this.machineEnd(index)
      }
    });

    this.tracker = new Tracker({
      assetPath
    });
  }

  hardReset () {
    this.signal.pressed = [true, true, true];
    this.signal.stop = [true, true, true];

    env.slots.splice(0, env.slots.length);
    let constFigures = [null, null, null];
    env.slots.push(new Slot(0, env.conf));
    constFigures[0] = env.slots[0].currentFigure();
    env.slots.push(new Slot(1, env.conf, constFigures));
    constFigures[1] = env.slots[1].currentFigure();
    env.slots.push(new Slot(2, env.conf, constFigures));

    if (this.tracker) {
      this.tracker.pause();
    }
    if (this.painter) {
      this.painter.handlerStop(0);
      this.painter.handlerStop(1);
      this.painter.handlerStop(2);
    }
    this.signal.stopAll();
  }

  tick () {
    let dirty = false;
    let stops = this.signal.stop;
    let stopable = true;

    for (let i = 0; i < env.slots.length; i++) {
      if (!this.signal.pressed[i]) {
        env.slots[i].roundTick();
      } else {
        let stop1 = stops[i];
        let stop2 = env.slots[i].stopTick(stopable);
        stopable = stopable && (stop1 == stop2);
      }
    }

    let currentStops = env.slots.map(slot => slot.speed === 0);
    dirty = currentStops.reduce((p, v, idx) => {
      return p || (v != stops[idx]);
    }, dirty); // 如果 stops 和 currentStops 有至少有一项不同, dirty = true
    this.signal.stop = currentStops;

    if (dirty) {
      let constFigures = this.getCurrentStopFigures();
      env.slots.forEach((slot) => {
        slot.hotReset(env.conf, constFigures.concat());
      });

      // 如果三个 slot 都停了，音乐结束
      if (currentStops[0] && currentStops[1] && currentStops[2]) {
        this.tracker.pause();

        // 如果开启了【已经摇到的数值不再选择】的配置，将当前数值放进 histroy，并重置 slot
        if (env.conf.autoRemoveEnable) {
          let item = [env.slots[0].currentFigure(), env.slots[1].currentFigure(), env.slots[2].currentFigure()];
          env.autoRemoveHistroy.push(item);

          // 权重设置为 0
          env.conf.candidates.forEach(candidate => {
            if (candidate.figureEquals(item)) {
              candidate.weight = 0;
            }
          });

          // 重置 slot
          env.slots[0].hotReset(env.conf, item);
          env.slots[1].hotReset(env.conf, item);
          env.slots[2].hotReset(env.conf, item);
        }
      }

      // 发送后端, 状态改变
      this.sendStatus();
    }
  }

  getState () {
    return {
      pressed : this.signal.pressed,
      stop : this.signal.stop,
      slots : this.getCurrentStopFigures(),
      trackerEnable : this.tracker.audioEnable,
      candidates : env.conf.candidates.map(c => c.extract()),
      autoRemoveEnable : env.conf.autoRemoveEnable,
      autoRemoveHistroy : env.autoRemoveHistroy
    };
  }

  /**
   * 返回这样的字符串列表:
   *   如果对应的 slot 停下来了，那么对应的位置为停下来的值；否则为 null
   * @returns {string[]} 比如 ['1', null, '6'], 表示第二个还在转
   */
  getCurrentStopFigures () {
    const stops = this.signal.stop;
    const ret = [null, null, null];

    for (let i = 0; i < stops.length; i++) {
      if (stops[i]) {
        ret[i] = env.slots[i].currentFigure();
      }
    }

    return ret;
  }

  /**
   * 事件
   * 拉杆启动
   */
  machineBegin () {
    this.signal.startAll();
    this.painter.handlerClick();
    // this.sendStatus(); -> 在 tick 中执行

    // 音频
    this.tracker.play();
  }

  /**
   * 事件
   * 按按钮, 停机器
   * @param {number} index 0,1,2
   */
  machineEnd (index) {
    this.signal.pressed[index] = true;
    this.painter.handlerStop(index);
    this.sendStatus();
  }

  /**
   * 上层控制
   * 是否放背景音乐
   * @param {boolean} enable
   */
  trackerEnable (enable) {
    this.tracker.setEnable(enable);
    this.sendStatus();
  }

  /**
   * 上层控制
   * 修改值域和每个值的权重
   * @param {ConfigCandidate[]} candidates 
   */
  weightChange (candidates) {
    // 检查 candidates 的代码 TODO

    env.conf.candidates = candidates.map(item => new ConfigCandidate(item.slot, item.weight, item.title));
    let constFigures = this.getCurrentStopFigures();

    env.slots[0].hotReset(env.conf, constFigures);
    env.slots[1].hotReset(env.conf, constFigures);
    env.slots[2].hotReset(env.conf, constFigures);
    // this.hardReset();
    this.sendStatus();
  }

  /**
   * 上层控制
   * 是否启用：已经摇到的数值不再选择
   * @param {boolean} enable
   */
  setAutoRemoveEnable (enable) {
    if (enable) {
      if (!env.conf.autoRemoveEnable) {
        env.conf.autoRemoveEnable = true;
        // 清空列表
        env.autoRemoveHistroy.splice(0, env.autoRemoveHistroy.length);
      }
    } else {
      if (env.conf.autoRemoveEnable) {
        env.conf.autoRemoveEnable = false;
        // 清空列表

        if (env.autoRemoveHistroy.length) {
          /** @type {Object<string, ConfigCandidate>} */
          let candidatesMapper = {};
          env.conf.candidates.forEach(candidate => {
            candidatesMapper[candidate.slot.join(',')] = candidate;
          });
  
          env.autoRemoveHistroy.forEach(items => {
            let key = items.join(',');
            if (candidatesMapper[key]) {
              candidatesMapper[key].weight = 10; // 恢复默认值
            }
          });
          env.autoRemoveHistroy.splice(0, env.autoRemoveHistroy.length);
        }
        
      }
    }
    this.sendStatus();
  }
}

export default Handler;

